package com.shanling.shanlingcontroller.http;



import android.support.annotation.NonNull;
import android.util.Log;

import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonWriter;
import com.shanling.shanlingcontroller.CustomApplication;
import com.shanling.shanlingcontroller.bean.ResultException;
import com.shanling.shanlingcontroller.utils.netstatus.NetUtils;
import com.google.gson.Gson;
import com.orhanobut.logger.Logger;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;


/**
 * Created by weiyu on 2019/1/16 0016.
 */

public class RetrofitBuildConfig {


    public RetrofitBuildConfig() {

    }
    public Retrofit.Builder getBuilder(String apiUrl) {
        Retrofit.Builder builder = new Retrofit.Builder();
        builder.client(getOkClient());
        builder.baseUrl(apiUrl);
        if(apiUrl.equals(HttpConstants.OTA_URL)){
            builder.addConverterFactory(GsonConverterFactory.create());
        }else {
            builder.addConverterFactory(new GsonDConverterFactory(new Gson()));
        }
        builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
        return builder;
    }

    private OkHttpClient getUnsafeOkHttpClient() {
        try {
            OkHttpClient.Builder okBuilder = new OkHttpClient.Builder();
            okBuilder.readTimeout(10, TimeUnit.SECONDS);
            okBuilder.connectTimeout(10, TimeUnit.SECONDS);
            okBuilder.writeTimeout(10, TimeUnit.SECONDS);
            okBuilder.addInterceptor(sLoggingInterceptor);
          //  okBuilder.addInterceptor(new sRewriteCacheControlInterceptor());
            return okBuilder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private OkHttpClient okHttpClientCache;

    /**
     * 返回 OkHttp 实例，保持不同类型唯一
     *
     * @return
     */
    public OkHttpClient getOkClient() {
        if (okHttpClientCache == null) {
            okHttpClientCache = getUnsafeOkHttpClient();
        }
        return okHttpClientCache;
    }


    public  final class GsonDConverterFactory extends Converter.Factory {
        private final Gson gson;
       public GsonDConverterFactory(Gson gson) {
            if (gson == null) throw new NullPointerException("gson == null");
            this.gson = gson;
        }

        @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
            return new GsonResponseBodyConverter < >(gson, type);
        }

        @Override public Converter < ?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
            TypeAdapter< ?> adapter = gson.getAdapter(TypeToken.get(type));
            return new GsonRequestBodyConverter < >(gson, adapter);
        }
    }

    private static final   Interceptor sLoggingInterceptor = new Interceptor() {

        @Override
        public Response intercept(Chain chain) throws IOException {
            final Request request = chain.request();
            Buffer requestBuffer = new Buffer();
            if (request.body() != null) {
                request.body().writeTo(requestBuffer);
            } else {
                Logger.d("LogTAG", "request.body() == null");
            }
            //打印url信息
            Logger.w(request.url() + (request.body() != null ? "?" + _parseParams(request.body(), requestBuffer) : ""));
            final Response response = chain.proceed(request);

            return response;
        }
    };

    @NonNull
    private static String _parseParams(RequestBody body, Buffer requestBuffer) throws UnsupportedEncodingException {
        if (body.contentType() != null && !body.contentType().toString().contains("multipart")) {
            return URLDecoder.decode(requestBuffer.readUtf8(), "UTF-8");
        }
        return "null";
    }


    final class GsonResponseBodyConverter < T > implements Converter< ResponseBody,
            T > {
        private final Gson gson;
        private final Type type;

        GsonResponseBodyConverter(Gson gson, Type type) {
            this.gson = gson;
            this.type = type;
        }

        /**
         * 针对数据返回成功、错误不同类型字段处理
         */
        @Override public T convert(ResponseBody value) throws IOException {
            String response = value.string();
            try {
                // 这里的type实际类型是 LoginUserEntity<User>  User就是user字段的对象。
                BaseResult result = gson.fromJson(response, BaseResult.class);
                if (result.hasSuccess()) {
                    return gson.fromJson(response, type);
                } else {
                    Log.e("HttpManager", "err==：" + response);
                    ErrorResult errResponse = gson.fromJson(response, ErrorResult.class);
                    throw new ResultException(errResponse.getMsg(),errResponse.getErrorCode()) ;
                }
            } finally {
                value.close();
            }
        }
    }



    final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
        private  final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
        private  final Charset UTF_8 = Charset.forName("UTF-8");

        private final Gson gson;
        private final TypeAdapter<T> adapter;

        GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
            this.gson = gson;
            this.adapter = adapter;
        }
        @Override
        public RequestBody convert(T value) throws IOException {
            Buffer buffer = new Buffer();
            Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
            JsonWriter jsonWriter = gson.newJsonWriter(writer);
            adapter.write(jsonWriter, value);
            jsonWriter.close();
            return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
        }
    }





    /**
     * 云端响应头拦截器，用来配置缓存策略
     * Dangerous interceptor that rewrites the server's cache-control header.
     */
    public  class sRewriteCacheControlInterceptor implements Interceptor {
        /**
         * 设缓存有效期为1天
         */
        long CACHE_STALE_SEC = 60 * 60 * 24;

        /**
         * 查询缓存的Cache-Control设置，为if-only-cache时只查询缓存而不会请求服务器，max-stale可以配合设置缓存失效时间
         */
        String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC;

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!NetUtils.isNetworkAvailable(CustomApplication.getInstance().getApplicationContext())) {
                request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
                Logger.e("no network");
            }
            Response originalResponse = chain.proceed(request);

            if (NetUtils.isNetworkAvailable(CustomApplication.getInstance().getApplicationContext())) {
                //有网的时候读接口上的@Headers里的配置，你可以在这里进行统一的设置
                String cacheControl = request.cacheControl().toString();
                return originalResponse.newBuilder()
                        .header("Cache-Control", cacheControl)
                        .removeHeader("Pragma")
                        .build();
            } else {
                return originalResponse.newBuilder()
                        .header("Cache-Control", "public, " + CACHE_CONTROL_CACHE)
                        .removeHeader("Pragma")
                        .build();
            }
        }
    };


}
